package com.company.game01;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RandomUtil;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import static com.company.game01.MyUtil.*;

public class MyFrame extends Frame implements Runnable {
    private static Tank heroTank1; // 我方坦克
    private static Tank heroTank2; // 我方坦克
    private static List<Tank> tanks; // 所有坦克集合
    public static final List<Boom> BOOMS = new LinkedList<>(); // 爆炸
    private static final ObjectPool<EnemyTank> OBJECT_POOL = new ObjectPool<>(EnemyTank.class, 4, 20);
    private static GameMap map; // 游戏地图
    public static int game_state; // 记录游戏状态
    private int enemyCount; // 记录敌方坦克总数
    private int hitCount; // 记录击中的敌方坦克总数
    private int menu_index; // 选中的菜单
    private int level = 1; // 记录游戏的当前关卡

    public MyFrame() {
        initFrame();
        initEventListener();
        ThreadUtil.execute(this);
    }

    private void newGame() {
        enemyCount = 0;
        hitCount = 0;
        map = new GameMap(level);

        if (menu_index == GAME_STATE_MENU) { // 开始游戏
            heroTank1 = new Tank(FRAME_WIDTH / 2 - (Tank.RADIUS << 2), FRAME_HEIGHT - Tank.RADIUS, Tank.DIR_UP, "");
            heroTank2 = new Tank(FRAME_WIDTH / 2 + (Tank.RADIUS << 2), FRAME_HEIGHT - Tank.RADIUS, Tank.DIR_UP, "");
        } else if (menu_index == GAME_STATE_RESUME) {
            resumeGame();
        }

        tanks = Collections.synchronizedList(new LinkedList<>());
        tanks.add(heroTank1);
        tanks.add(heroTank2);
        ThreadUtil.execute(() -> {
            while (enemyCount < ENEMY_MAX_COUNT && (heroTank1.isVisible() || heroTank2.isVisible())) {
                ThreadUtil.sleep(30);
//                synchronized (this) { }  // 控制敌方，最大生产坦克数为4
                int size = heroTank1.isVisible() && heroTank2.isVisible() ? 6 : 5;
                if (tanks.size() < size && enemyCount < ENEMY_MAX_COUNT) initTank();
            }
        });
    }

    private void resumeGame() {
        if (heroTank1 != null) {
            if (heroTank1.isVisible()) {
                heroTank1 = new Tank(FRAME_WIDTH / 2 - (Tank.RADIUS << 2), FRAME_HEIGHT - Tank.RADIUS, Tank.DIR_UP, heroTank1.getName());
            }
        } else {
            heroTank1 = new Tank(FRAME_WIDTH / 2 - (Tank.RADIUS << 2), FRAME_HEIGHT - Tank.RADIUS, Tank.DIR_UP, "");
        }
        if (heroTank2 != null) {
            if (heroTank2.isVisible()) {
                heroTank2 = new Tank(FRAME_WIDTH / 2 + (Tank.RADIUS << 2), FRAME_HEIGHT - Tank.RADIUS, Tank.DIR_UP, heroTank2.getName());
            }
        } else {
            heroTank2 = new Tank(FRAME_WIDTH / 2 + (Tank.RADIUS << 2), FRAME_HEIGHT - Tank.RADIUS, Tank.DIR_UP, "");
        }
    }

    private void initTank() {
        ThreadUtil.sleep(ENEMY_BORN_INTERVAL);
        int x, y = TOP + Tank.RADIUS + Tank.BloodBar.BAR_HEIGHT * 6;
        int[] born_x = {Tank.RADIUS, FRAME_WIDTH - Tank.RADIUS >> 1, FRAME_WIDTH - Tank.RADIUS};
        do { // 处理坦克出生重叠
            x = born_x[RandomUtil.randomInt(born_x.length)];
        } while (isBornTouch(tanks, x, y));
        EnemyTank enemyTank = OBJECT_POOL.get();
        enemyTank.setX(x);
        enemyTank.setY(y);
        enemyTank.setDir(Tank.DIR_DOWN);
        enemyTank.setHp(Tank.DEFAULT_HP);
        enemyTank.setPreX(x);
        enemyTank.setPreY(y);
        enemyTank.setVisible(true);
        tanks.add(enemyTank);
        enemyCount++;
    }

    private void drawRun(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
        map.draw(g);

        if (heroTank1.isVisible()) heroTank1.draw(g);
        else tanks.remove(heroTank1);
        if (heroTank2.isVisible()) heroTank2.draw(g);
        else tanks.remove(heroTank2);

        for (int i = 0; i < tanks.size(); i++) {
            Tank enemyTank = tanks.get(i);
            if (enemyTank instanceof EnemyTank) {
                if (enemyTank.isVisible()) {
                    enemyTank.draw(g); // 绘制敌方坦克
                    for (int j = 0; j < enemyTank.getBullets().size(); j++) {
                        Bullet bullet = enemyTank.getBullets().get(j);
                        if (heroTank1.isVisible() && isHit(bullet, heroTank1)) { // 判断是否击中，我方坦克1
                            BOOMS.add(new Boom(heroTank1.getX() - 5, heroTank1.getY() - 5));
                        } else if (heroTank2.isVisible() && isHit(bullet, heroTank2)) { // 判断是否击中，我方坦克2
                            BOOMS.add(new Boom(heroTank2.getX() - 5, heroTank2.getY() - 5));
                        }
                    }
                } else {
                    tanks.remove(enemyTank);
                    OBJECT_POOL.ret((EnemyTank) enemyTank);
                }
            }
        }

        // 判断是否击中敌方坦克
        for (int i = 0; heroTank1.isVisible() && i < heroTank1.getBullets().size(); i++) {
            Bullet bullet = heroTank1.getBullets().get(i);
            for (int j = 0; j < tanks.size(); j++) {
                Tank enemyTank = tanks.get(j);
                if (enemyTank instanceof EnemyTank) {
                    boolean hit = isHit(bullet, enemyTank);
                    if (hit) {
                        BOOMS.add(new Boom(enemyTank.getX() - 5, enemyTank.getY() - 10));
                    }
                }
            }
        }

        for (int i = 0; heroTank2.isVisible() && i < heroTank2.getBullets().size(); i++) {
            Bullet bullet = heroTank2.getBullets().get(i);
            for (int j = 0; j < tanks.size(); j++) {
                Tank enemyTank = tanks.get(j);
                if (enemyTank instanceof EnemyTank) {
                    boolean hit = isHit(bullet, enemyTank);
                    if (hit) {
                        BOOMS.add(new Boom(enemyTank.getX() - 5, enemyTank.getY() - 10));
                    }
                }
            }
        }

        map.drawCover(g);

        // 绘制爆炸效果
        for (int i = 0; i < BOOMS.size(); i++) {
            Boom boom = BOOMS.get(i);
            boom.draw(g);
            if (boom.getLife() == 15) {
                BOOMS.remove(boom);
            }
        }

        // 处理坦克重叠
        isTouch(tanks);

        // 处理地图相关
        for (int i = 0; i < tanks.size(); i++) {
            Tank tank = tanks.get(i);
            map.isHitTiles(tank.getBullets());
            map.isCollideTank(tank);
        }

    }

    private void drawMenu(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);

        int x = FRAME_WIDTH - 50 >> 1; // menu_x = (frame_with - font_with) / 2
        int y = FRAME_HEIGHT / 3;
        int dis = 30;
        g.setColor(Color.WHITE);
        String[] menus = {"开始游戏", "继续游戏", "游戏帮助", "关于游戏", "退出游戏"};
        for (int i = 0; i < menus.length; i++) {
            if (menu_index == i) g.setColor(Color.RED);
            else g.setColor(Color.WHITE);
            g.drawString(menus[i], x, y + (dis * i));
        }
    }

    private static final Image image = getImage("/static/over.gif");

    private void drawLost(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
        int imgW = 417;
        int imgH = 406;
        g.drawImage(image, FRAME_WIDTH - imgW >> 1, FRAME_HEIGHT - imgH >> 1, null);
        g.setColor(Color.WHITE);
        g.drawString("ESC键退出游戏", 10, FRAME_HEIGHT - 20);
        g.drawString("ENTER键继续游戏", FRAME_WIDTH - 115, FRAME_HEIGHT - 20);
        g.drawString("过关失败", FRAME_WIDTH / 2 - 30, 50);
    }

    private void drawPass(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
        int imgW = 417;
        int imgH = 406;
        g.drawImage(image, FRAME_WIDTH - imgW >> 1, FRAME_HEIGHT - imgH >> 1, null);
        g.setColor(Color.WHITE);
        g.drawString("ESC键退出游戏", 10, FRAME_HEIGHT - 20);
        g.drawString("ENTER键继续游戏", FRAME_WIDTH - 115, FRAME_HEIGHT - 20);
        g.drawString("过关成功", FRAME_WIDTH / 2 - 30, 50);
    }

    private boolean isHit(Bullet bullet, Tank tank) {
//        boolean touch = isTouch(tank.getX(), tank.getY(), Tank.RADIUS, bullet.getX(), bullet.getY());
        boolean touch = bullet.getRect().intersects(tank.getRect());
        if (touch) {
            bullet.setVisible(false);
            int hp = tank.getHp() - bullet.getAtk();
            if (hp > 0) {
                tank.setHp(hp);
            } else {
                tank.setVisible(false);
                tank.setState(Tank.STATE_DIE);
                if (!(tank instanceof EnemyTank)) {
                    if (heroTank1.isVisible() || heroTank2.isVisible()) return true;
                    ThreadUtil.execute(() -> { // 击毁我方所有坦克
                        ThreadUtil.sleep(3000);
                        MyFrame.game_state = GAME_STATE_MENU;
                        level = 1;
                    });
                } else {
                    // 击毁最后一辆坦克的逻辑处理
                    if (++hitCount == ENEMY_MAX_COUNT) {
                        ThreadUtil.execute(() -> {
                            ThreadUtil.sleep(3000);
                            MyFrame.game_state = GAME_STATE_PASS;
                            level++;
                        });
                    }
                }
            }
        }
        return touch;
    }

    @Override
    public void update(Graphics g) {
        switch (game_state) {
            case GAME_STATE_MENU:
                drawMenu(g);
                break;
            case GAME_STATE_RUN:
                drawRun(g);
                break;
            case GAME_STATE_LOST:
                drawLost(g);
                break;
            case GAME_STATE_PASS:
                drawPass(g);
                break;
        }
    }

    @Override
    public void run() { // 界面重绘线程
        while (true) {
            repaint();
            ThreadUtil.sleep(30);
        }
    }

    public static int TOP = 0;

    private void initFrame() {
        setSize(FRAME_WIDTH, FRAME_HEIGHT);
        setTitle("坦克大战");
        setLocationRelativeTo(null);
        setResizable(false);
        setVisible(true);
        TOP = getInsets().top;
    }

    private void initEventListener() {
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                switch (game_state) {
                    case GAME_STATE_MENU:
                        switch (e.getKeyCode()) {
                            case KeyEvent.VK_UP:
                            case KeyEvent.VK_W:
                                if (menu_index > 0) menu_index--;
                                break;
                            case KeyEvent.VK_DOWN:
                            case KeyEvent.VK_S:
                                if (menu_index < 4) menu_index++;
                                break;
                            case KeyEvent.VK_ENTER:
                            case KeyEvent.VK_SPACE:
                                game_state = menu_index + 1;
                                switch (game_state) {
                                    case GAME_STATE_RUN:
                                        newGame();
                                        Audio.playStart();
                                        break;
                                    case GAME_STATE_RESUME:
                                    case GAME_STATE_HELP:
                                    case GAME_STATE_ABOUT:
                                    case GAME_STATE_EXIT:
                                        System.exit(0);
                                        break;

                                }
                                break;
                        }
                        break;
                    case GAME_STATE_RUN:
                        switch (e.getKeyCode()) {
                            case KeyEvent.VK_UP:
                                heroTank2.setDir(Tank.DIR_UP);
                                heroTank2.setState(Tank.STATE_MOVE);
                                break;
                            case KeyEvent.VK_W:
                                heroTank1.setDir(Tank.DIR_UP);
                                heroTank1.setState(Tank.STATE_MOVE);
                                break;
                            case KeyEvent.VK_DOWN:
                                heroTank2.setDir(Tank.DIR_DOWN);
                                heroTank2.setState(Tank.STATE_MOVE);
                                break;
                            case KeyEvent.VK_S:
                                heroTank1.setDir(Tank.DIR_DOWN);
                                heroTank1.setState(Tank.STATE_MOVE);
                                break;
                            case KeyEvent.VK_LEFT:
                                heroTank2.setDir(Tank.DIR_LEFT);
                                heroTank2.setState(Tank.STATE_MOVE);
                                break;
                            case KeyEvent.VK_A:
                                heroTank1.setDir(Tank.DIR_LEFT);
                                heroTank1.setState(Tank.STATE_MOVE);
                                break;
                            case KeyEvent.VK_RIGHT:
                                heroTank2.setDir(Tank.DIR_RIGHT);
                                heroTank2.setState(Tank.STATE_MOVE);
                                break;
                            case KeyEvent.VK_D:
                                heroTank1.setDir(Tank.DIR_RIGHT);
                                heroTank1.setState(Tank.STATE_MOVE);
                                break;
                        }
                        break;
                    case GAME_STATE_LOST:
                        switch (e.getKeyCode()) {
                            case KeyEvent.VK_ESCAPE:
                                System.exit(0);
                                break;
                            case KeyEvent.VK_ENTER:
                                menu_index = GAME_STATE_RESUME;
                                newGame();
                                game_state = GAME_STATE_RUN;
                                Audio.playStart();
                                break;
                        }
                        break;
                    case GAME_STATE_PASS:
                        switch (e.getKeyCode()) {
                            case KeyEvent.VK_ESCAPE:
                                System.exit(0);
                                break;
                            case KeyEvent.VK_ENTER:
                                menu_index = GAME_STATE_RESUME;
                                newGame();
                                Audio.playStart();
                                game_state = GAME_STATE_RUN;
                                break;
                        }
                        break;
                }
            }

            @Override // 按键松开
            public void keyReleased(KeyEvent e) {
                if (game_state == GAME_STATE_RUN) {
                    switch (e.getKeyCode()) {
                        case KeyEvent.VK_W:
                        case KeyEvent.VK_S:
                        case KeyEvent.VK_A:
                        case KeyEvent.VK_D:
                            heroTank1.setState(Tank.STATE_STAND);
                            break;
                        case KeyEvent.VK_UP:
                        case KeyEvent.VK_DOWN:
                        case KeyEvent.VK_LEFT:
                        case KeyEvent.VK_RIGHT:
                            heroTank2.setState(Tank.STATE_STAND);
                            break;
                        case KeyEvent.VK_J:
                            heroTank1.fire();
                            break;
                        case KeyEvent.VK_X:
                            heroTank2.fire();
                            break;
                    }
                }
            }
        });
    }
}
